﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized; // For INotifyCollectionChanged
using System.Globalization;
using System.IO; // 添加 System.IO for IOException
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Platform;
using Avalonia.Data.Converters; // May need if using CollectionViewSource in code
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using SerialTool.Models;
using SerialTool.Services;
using System.Text.Json; // <--- Add this

namespace SerialTool.ViewModels;

public partial class MainWindowViewModel : ViewModelBase
{
    private SerialPort? _serialPort;
    private string _commandToSend = string.Empty;
    private bool _isConnected = false;
    private bool _hexDisplay = false;
    
    // 定时发送相关
    private DispatcherTimer? _sendTimer;
    [ObservableProperty]
    private bool _isScheduled = false;
    [ObservableProperty]
    private string _sendInterval = "1000"; // 默认 1000ms
    [ObservableProperty]
    private bool _canSendManually = true; // 控制手动发送按钮状态

    private int _sentBytes = 0;
    private int _receivedBytes = 0;

    // 新增：自动滚动控制
    [ObservableProperty]
    private bool _autoScrollEnabled = true;

    // 新增：过滤控制属性
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(FilteredMessages))] // Keep this conceptually, filter logic handles update
    private bool _showSent = true;

    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(FilteredMessages))] // Keep this conceptually, filter logic handles update
    private bool _showReceived = true;

    [ObservableProperty]
    private ObservableCollection<string> _availablePorts = new();

    [ObservableProperty]
    private string _selectedPort = string.Empty;

    [ObservableProperty]
    private List<int> _commonBaudRates = SerialPortSettings.CommonBaudRates;

    [ObservableProperty]
    private int _baudRate = 9600;

    [ObservableProperty]
    private List<int> _dataBitsOptions = new List<int> { 5, 6, 7, 8 };

    [ObservableProperty]
    private int _selectedDataBits = 8;

    [ObservableProperty]
    private List<Parity> _parityOptions = Enum.GetValues(typeof(Parity)).Cast<Parity>().ToList();

    [ObservableProperty]
    private Parity _selectedParity = Parity.None;

    [ObservableProperty]
    private List<StopBits> _stopBitsOptions = Enum.GetValues(typeof(StopBits)).Cast<StopBits>().Where(sb => sb != StopBits.None).ToList();

    [ObservableProperty]
    private StopBits _selectedStopBits = StopBits.One;

    [ObservableProperty]
    private List<string> _sendEncodingOptions = new List<string> { "ASCII", "UTF8", "HEX" };

    [ObservableProperty]
    private string _selectedSendEncoding = "ASCII";

    [ObservableProperty]
    private ObservableCollection<string> _logEntries = new();

    // 底层原始消息列表
    private readonly ObservableCollection<LogMessage> _messages = new();
    
    // 用于UI绑定的过滤后的集合
    [ObservableProperty]
    private ObservableCollection<LogMessage> _filteredMessages = new();

    // 新增：预设指令相关
    [ObservableProperty]
    private string _newPresetName = string.Empty;
    [ObservableProperty]
    private string _newPresetCommandString = string.Empty;
    [ObservableProperty]
    private string _newPresetEncoding = "ASCII";
    [ObservableProperty]
    private ObservableCollection<PresetCommandViewModel> _presetCommands = new();

    // 应用设置对象
    private AppSettings _appSettings = new AppSettings();

    // 协议配置相关
    [ObservableProperty]
    private ProtocolConfigViewModel _protocolConfig;

    public string CommandToSend 
    { 
        get => _commandToSend; 
        set => SetProperty(ref _commandToSend, value); 
    }

    public bool HexDisplay 
    { 
        get => _hexDisplay; 
        set 
        {
            if (SetProperty(ref _hexDisplay, value))
            {
                SaveSettings(); // 直接在 setter 中调用 SaveSettings
            }
        } 
    }

    public string ConnectionButtonText => _isConnected ? "断开" : "连接";

    public string ConnectionStatus => _isConnected ? "已连接" : "未连接";

    public int SentBytes 
    { 
        get => _sentBytes; 
        set => SetProperty(ref _sentBytes, value); 
    }

    public int ReceivedBytes 
    { 
        get => _receivedBytes; 
        set => SetProperty(ref _receivedBytes, value); 
    }

    public MainWindowViewModel()
    {
        // 首先加载应用设置
        LoadSettings();
        
        // 然后刷新可用端口列表
        RefreshAvailablePorts();
        
        // 设置事件监听
        _messages.CollectionChanged += Messages_CollectionChanged;
        
        // 加载预设命令
        LoadPresets();

        // 监听属性变化，在变化时保存设置
        PropertyChanged += (sender, args) => {
            // 当这些属性变化时，保存设置
            if (args.PropertyName == nameof(BaudRate) ||
                args.PropertyName == nameof(SelectedDataBits) ||
                args.PropertyName == nameof(SelectedParity) ||
                args.PropertyName == nameof(SelectedStopBits) ||
                args.PropertyName == nameof(SelectedSendEncoding) ||
                args.PropertyName == nameof(SendInterval) ||
                args.PropertyName == nameof(ShowSent) ||
                args.PropertyName == nameof(ShowReceived) ||
                args.PropertyName == nameof(AutoScrollEnabled))
            {
                SaveSettings();
            }
        };

        // 自动保存设置的计时器 (每30秒)
        var autoSaveTimer = new DispatcherTimer
        {
            Interval = TimeSpan.FromSeconds(30)
        };
        autoSaveTimer.Tick += (s, e) => SaveSettings();
        autoSaveTimer.Start();

        // 初始化协议配置
        _protocolConfig = new ProtocolConfigViewModel(this);
    }

    // 当原始集合变化时，重新应用过滤
    private void Messages_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
    {
        // 简单起见，完全重新生成过滤后的列表
        // 对于大量消息，可能需要更优化的处理（只添加/删除变化的项）
        ApplyFilter();
    }

    // 应用过滤逻辑
    private void ApplyFilter()
    {
        FilteredMessages.Clear();
        foreach (var message in _messages)
        {
            if (FilterMessagesPredicate(message))
            {
                FilteredMessages.Add(message);
            }
        }
    }

    // 过滤条件判断
    private bool FilterMessagesPredicate(LogMessage message)
    {
        if (message.Direction == LogMessageDirection.Sent && ShowSent) return true;
        if (message.Direction == LogMessageDirection.Received && ShowReceived) return true;
        return false;
    }
    
    // 当过滤 CheckBox 改变时，重新应用过滤
    partial void OnShowSentChanged(bool value)
    {
        ApplyFilter();
    }
    
    partial void OnShowReceivedChanged(bool value)
    {
        ApplyFilter();
    }

    // 定时发送 CheckBox 变化时的处理
    partial void OnIsScheduledChanged(bool value)
    {
        if (value)
        {
            StartScheduledSend();
        }
        else
        {
            StopScheduledSend();
        }
    }
    
    // 发送间隔文本框变化时的处理 (如果需要在定时器运行时动态调整间隔)
    partial void OnSendIntervalChanged(string value)
    {
         if (_sendTimer != null && _sendTimer.IsEnabled)
         {
             if (int.TryParse(value, out int interval) && interval > 0)
             {
                 _sendTimer.Interval = TimeSpan.FromMilliseconds(interval);
                 LogEntries.Add($"定时发送间隔已更新为: {interval} ms");
             }
             else
             {
                 // 如果新间隔无效，可以停止定时或保持旧间隔，这里选择停止
                 LogEntries.Add($"错误: 无效的发送间隔 '{value}'，已停止定时发送。");
                 IsScheduled = false; // 会触发 OnIsScheduledChanged 来停止定时器
             }
         }
    }

    private void StartScheduledSend()
    {
        if (!_isConnected)
        {
            LogEntries.Add("错误: 未连接串口，无法启动定时发送。");
            IsScheduled = false; // 重置 CheckBox 状态
            return;
        }
        
        if (int.TryParse(SendInterval, out int interval) && interval > 0)
        {
            _sendTimer ??= new DispatcherTimer();
            _sendTimer.Interval = TimeSpan.FromMilliseconds(interval);
            _sendTimer.Tick += SendTimer_Tick; 
            _sendTimer.Start();
            CanSendManually = false; // 禁用手动发送按钮
            LogEntries.Add($"定时发送已启动，间隔: {interval} ms");
        }
        else
        {
            LogEntries.Add($"错误: 无效的发送间隔 '{SendInterval}'。");
            IsScheduled = false; // 重置 CheckBox 状态
        }
    }

    private void StopScheduledSend()
    {
        if (_sendTimer != null && _sendTimer.IsEnabled)
        {
            _sendTimer.Stop();
            _sendTimer.Tick -= SendTimer_Tick; // 移除事件处理器，避免内存泄漏
            CanSendManually = true; // 启用手动发送按钮
            LogEntries.Add("定时发送已停止。");
        }
    }

    // 定时器触发事件
    private async void SendTimer_Tick(object? sender, EventArgs e)
    {
        // 直接调用发送逻辑
        await ExecuteSendLogic();
    }

    [RelayCommand]
    private void RefreshPorts()
    {
        RefreshAvailablePorts();
    }

    [RelayCommand]
    private void Connect()
    {
        if (_isConnected)
        {
            DisconnectPort();
        }
        else
        {
            ConnectPort();
        }
    }

    [RelayCommand]
    private void ClearLog() 
    {
        _messages.Clear(); // 清空原始列表会自动触发 ApplyFilter 来清空 FilteredMessages
        // SentBytes = 0;
        // ReceivedBytes = 0;
    }

    [RelayCommand]
    private async Task ExportLog()
    {
        try
        {
            // 获取当前应用程序的主窗口实例
            var mainWindow = (Avalonia.Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow;
            if (mainWindow == null)
            {
                LogEntries.Add("[ERROR] 无法获取主窗口实例");
                // 添加Toast提示
                ToastService.Instance.ShowToast("导出失败", "无法获取主窗口实例", ToastType.Error);
                return;
            }

            // 使用新的StorageProvider API
            var topLevel = TopLevel.GetTopLevel(mainWindow);
            if (topLevel?.StorageProvider == null)
            {
                LogEntries.Add("[ERROR] 无法获取存储提供程序");
                ToastService.Instance.ShowToast("导出失败", "无法获取存储提供程序", ToastType.Error);
                return;
            }

            // 创建保存文件选项
            var options = new FilePickerSaveOptions
            {
                Title = "导出通信日志",
                SuggestedFileName = $"通信日志_{DateTime.Now:yyyyMMdd_HHmmss}",
                FileTypeChoices = new[]
                {
                    new FilePickerFileType("文本文件") { Patterns = new[] { "*.txt" } },
                    new FilePickerFileType("CSV文件") { Patterns = new[] { "*.csv" } },
                    new FilePickerFileType("所有文件") { Patterns = new[] { "*" } }
                }
            };

            // 显示保存文件对话框
            var file = await topLevel.StorageProvider.SaveFilePickerAsync(options);
            if (file == null)
            {
                // 用户取消了操作
                return;
            }

            // 获取文件路径和扩展名
            string filePath = file.Path.LocalPath;
            string fileExtension = System.IO.Path.GetExtension(filePath).ToLowerInvariant();
            
            // 按照当前过滤器导出消息
            var messagesToExport = FilteredMessages.ToList();
            LogEntries.Add($"[INFO] 正在导出 {messagesToExport.Count} 条消息...");
            
            // 添加Toast提示
            ToastService.Instance.ShowToast("导出中", $"正在导出 {messagesToExport.Count} 条消息...", ToastType.Information);

            // 打开文件流进行写入
            using (var stream = await file.OpenWriteAsync())
            using (var writer = new StreamWriter(stream))
            {
                if (fileExtension == ".csv")
                {
                    // CSV格式：时间,方向,内容,HEX
                    await writer.WriteLineAsync("时间,方向,内容,HEX数据");
                    foreach (var msg in messagesToExport)
                    {
                        string direction = msg.Direction == LogMessageDirection.Sent ? "发送" : "接收";
                        string hexData = BitConverter.ToString(msg.RawBytes ?? Array.Empty<byte>()).Replace("-", " ");
                        // 确保CSV字段正确转义（添加引号，并将内容中的引号替换为两个引号）
                        string escapedContent = $"\"{msg.Content.Replace("\"", "\"\"")}\"";
                        await writer.WriteLineAsync($"{msg.Timestamp:yyyy-MM-dd HH:mm:ss.fff},{direction},{escapedContent},{hexData}");
                    }
                }
                else // 默认为文本格式
                {
                    // 文本格式：[时间] [方向] 内容
                    // HEX数据单独一行
                    foreach (var msg in messagesToExport)
                    {
                        string direction = msg.Direction == LogMessageDirection.Sent ? "发送" : "接收";
                        string hexData = BitConverter.ToString(msg.RawBytes ?? Array.Empty<byte>()).Replace("-", " ");
                        await writer.WriteLineAsync($"[{msg.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{direction}] {msg.Content}");
                        await writer.WriteLineAsync($"HEX: {hexData}");
                        await writer.WriteLineAsync(new string('-', 80)); // 分隔线
                    }
                }
            }

            LogEntries.Add($"[INFO] 日志已成功导出到: {filePath}");
            
            // 添加Toast提示
            ToastService.Instance.ShowToast("导出成功", $"日志已导出到: {System.IO.Path.GetFileName(filePath)}", ToastType.Success);
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] 导出日志失败: {ex.Message}");
            
            // 添加Toast提示
            ToastService.Instance.ShowToast("导出失败", $"错误: {ex.Message}", ToastType.Error);
        }
    }

    // 添加意见反馈命令
    [RelayCommand]
    private void SendFeedback()
    {
        try
        {
            string emailAddress = "1034639560@qq.com";
            string subject = "SerialTool 意见反馈";
            string body = $"应用版本: 1.0\n系统信息: {Environment.OSVersion}\n\n请在此处描述您的问题或建议:\n\n";
            
            // 构建mailto URI
            string mailtoUri = $"mailto:{emailAddress}?subject={Uri.EscapeDataString(subject)}&body={Uri.EscapeDataString(body)}";
            
            // 使用系统默认浏览器或邮件客户端打开
            if (OperatingSystem.IsWindows())
            {
                // Windows
                System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
                {
                    FileName = mailtoUri,
                    UseShellExecute = true
                });
            }
            else if (OperatingSystem.IsMacOS())
            {
                // macOS
                System.Diagnostics.Process.Start("open", mailtoUri);
            }
            else if (OperatingSystem.IsLinux())
            {
                // Linux
                System.Diagnostics.Process.Start("xdg-open", mailtoUri);
            }
            
            LogEntries.Add("[INFO] 已打开反馈邮件窗口");
            ToastService.Instance.ShowToast("意见反馈", "已打开邮件窗口，请填写反馈内容", ToastType.Information);
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] 打开邮件客户端失败: {ex.Message}");
            ToastService.Instance.ShowToast("打开失败", $"无法打开邮件客户端: {ex.Message}", ToastType.Error);
        }
    }
    
    // 添加打开URL命令
    [RelayCommand]
    private void OpenUrl(string url)
    {
        try
        {
            LogEntries.Add($"[INFO] 正在打开网址: {url}");
            
            if (OperatingSystem.IsWindows())
            {
                // Windows
                System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
                {
                    FileName = url,
                    UseShellExecute = true
                });
            }
            else if (OperatingSystem.IsMacOS())
            {
                // macOS
                System.Diagnostics.Process.Start("open", url);
            }
            else if (OperatingSystem.IsLinux())
            {
                // Linux
                System.Diagnostics.Process.Start("xdg-open", url);
            }
            
            LogEntries.Add("[INFO] 已在浏览器中打开网址");
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] 打开网址失败: {ex.Message}");
            ToastService.Instance.ShowToast("打开失败", $"无法打开网址: {ex.Message}", ToastType.Error);
        }
    }

    // 手动发送命令
    [RelayCommand(CanExecute = nameof(CanSendManually))] // 绑定 CanExecute
    private async Task Send()
    {
        await ExecuteSendLogic();
    }

    // 修改：添加预设指令命令，改为返回Task
    [RelayCommand]
    public async Task AddPresetCommand()
    {
        LogEntries.Add("[DEBUG] 准备添加预设命令...");
        LogEntries.Add($"[DEBUG] 名称: '{NewPresetName}', 命令: '{NewPresetCommandString}'");
        
        if (string.IsNullOrWhiteSpace(NewPresetName) || string.IsNullOrEmpty(NewPresetCommandString))
        {
            LogEntries.Add("[ERROR] 预设名称或命令不能为空");
            // 添加Toast提示
            ToastService.Instance.ShowToast("添加失败", "预设名称或命令不能为空", ToastType.Warning);
            return;
        }
        
        bool nameExists = PresetCommands.Any(pvm => pvm.Name == NewPresetName);
        LogEntries.Add($"[DEBUG] 检查名称 '{NewPresetName}' 是否存在: {nameExists}");
        
        if (nameExists)
        {
             LogEntries.Add($"[ERROR] 预设名称 '{NewPresetName}' 已存在");
             // 添加确认对话框
             bool overwrite = await DialogService.Instance.ShowConfirmationAsync(
                 "名称已存在", 
                 $"预设名称 '{NewPresetName}' 已存在。是否要覆盖现有预设？", 
                 "覆盖", "取消");
             
             if (overwrite)
             {
                 // 删除同名预设
                 var existingPreset = PresetCommands.First(pvm => pvm.Name == NewPresetName);
                 PresetCommands.Remove(existingPreset);
                 LogEntries.Add($"[INFO] 已删除同名预设，准备添加新预设");
             }
             else
             {
                 LogEntries.Add($"[INFO] 用户取消了覆盖操作");
                 return;
             }
        }

        LogEntries.Add($"[DEBUG] 编码类型: '{NewPresetEncoding}'");
        LogEntries.Add("[DEBUG] 创建预设命令模型...");
        var newPresetModel = new PresetCommand
        {
            Name = NewPresetName,
            CommandString = NewPresetCommandString,
            EncodingType = NewPresetEncoding
        };
        LogEntries.Add($"[DEBUG] 预设命令模型已创建，编码类型: {newPresetModel.EncodingType}");

        // 创建 ViewModel 并添加到集合
        LogEntries.Add("[DEBUG] 创建预设命令视图模型...");
        var newPresetViewModel = new PresetCommandViewModel(newPresetModel, this); 
        LogEntries.Add("[DEBUG] 预设命令视图模型已创建，添加到集合...");
        PresetCommands.Add(newPresetViewModel);
        LogEntries.Add($"[DEBUG] 已将预设 '{NewPresetName}' 添加到集合");
        SavePresets(); // <--- Add SavePresets call
        
        // 添加Toast提示
        ToastService.Instance.ShowToast("添加成功", $"预设命令 '{NewPresetName}' 已添加", ToastType.Success);
        
        // 清空输入框
        LogEntries.Add("[DEBUG] 清空输入字段...");
        NewPresetName = string.Empty;
        NewPresetCommandString = string.Empty;
        LogEntries.Add("[DEBUG] 预设命令添加完成");
    }

    // 修改：供 PresetCommandViewModel 调用的方法
    public async Task SendCommandFromPreset(string commandString, string encodingType) // 添加 encodingType 参数
    {
        LogEntries.Add($"[DEBUG] Sending preset. Command: '{commandString}', Encoding: '{encodingType}'");
        // 将预设指令内容和编码填入主发送区
        CommandToSend = commandString;
        SelectedSendEncoding = encodingType; // 设置主发送区的编码
        
        // 执行发送
        await ExecuteSendLogic();
    }

    // 修改：实际的发送逻辑，添加可选的编码和命令覆盖参数
    public async Task ExecuteSendLogic(string? commandOverride = null, string? encodingOverride = null)
    {
        LogEntries.Add($"[DEBUG] ExecuteSendLogic: Command Override: '{commandOverride}'");
        LogEntries.Add($"[DEBUG] ExecuteSendLogic: Encoding Override: '{encodingOverride}'");
        LogEntries.Add($"[DEBUG] ExecuteSendLogic: Selected Encoding: '{SelectedSendEncoding}'");
        
        // 检查串口是否打开
        if (_serialPort == null || !_serialPort.IsOpen)
        {
            LogEntries.Add("[ERROR] Serial port is not open");
            return;
        }

        // 确定要发送的命令
        string commandToSend = commandOverride ?? CommandToSend;
        
        // 确定要使用的编码
        string encodingToUse = encodingOverride ?? SelectedSendEncoding;
        
        if (string.IsNullOrEmpty(commandToSend))
        {
            LogEntries.Add("[ERROR] No command to send");
            return;
        }

        LogEntries.Add($"[DEBUG] Command to send: '{commandToSend}'");
        LogEntries.Add($"[DEBUG] Encoding to use: '{encodingToUse}'");

        try
        {
            byte[] dataToSend;
            
            // 根据选择的编码格式进行处理
            if (encodingToUse == "HEX")
            {
                LogEntries.Add("[INFO] 使用HEX编码转换数据...");
                try
                {
                    dataToSend = ConvertHexStringToByteArray(commandToSend);
                }
                catch (FormatException ex)
                {
                    LogEntries.Add($"[ERROR] HEX格式错误：{ex.Message}");
                    LogEntries.Add("[提示] HEX格式应为偶数个十六进制字符，可包含空格");
                    // 添加弹窗提示，这种是用户操作错误，应该提醒用户正确格式
                    await DialogService.Instance.ShowMessageAsync("HEX格式错误", 
                        "HEX格式应为偶数个十六进制字符，可包含空格。\n例如: \"AA BB CC\" 或 \"AABBCC\"");
                    return;
                }
            }
            else if (encodingToUse == "UTF8")
            {
                LogEntries.Add("[INFO] 使用UTF8编码转换数据...");
                dataToSend = Encoding.UTF8.GetBytes(commandToSend);
            }
            else
            {
                LogEntries.Add("[INFO] 使用ASCII编码转换数据...");
                dataToSend = Encoding.ASCII.GetBytes(commandToSend);
            }

            // 应用协议处理
            if (ProtocolConfig.IsEnabled)
            {
                dataToSend = ProtocolService.Instance.FormatSendData(dataToSend);
                LogEntries.Add($"[INFO] 已应用协议 '{ProtocolConfig.SelectedProtocolType}' 处理数据");
            }

            if (dataToSend.Length > 0)
            {
                LogEntries.Add($"[INFO] 数据长度：{dataToSend.Length} 字节，正在写入串口...");
                
                // 执行写入操作
                _serialPort.Write(dataToSend, 0, dataToSend.Length);
                
                // 更新统计信息并添加日志
                SentBytes += dataToSend.Length;
                string source = IsScheduled ? "定时" : "手动"; 
                
                // 添加到消息列表
                AddLogMessage(new LogMessage
                { 
                    Direction = LogMessageDirection.Sent, 
                    Content = commandToSend, 
                    RawBytes = dataToSend 
                });
                
                // 显示发送成功信息
                LogEntries.Add($"[SUCCESS] 已发送 ({encodingToUse} - {source}): {commandToSend}"); 
            }
            else
            {
                LogEntries.Add("[WARNING] 数据长度为0，未发送任何数据");
                // 添加Toast提示
                ToastService.Instance.ShowToast("警告", "数据长度为0，未发送任何数据", ToastType.Warning);
            }
        }
        catch (TimeoutException)
        {
            LogEntries.Add("[ERROR] 发送超时：串口设备未响应");
            LogEntries.Add("[提示] 请检查设备是否正常工作或尝试重新连接");
            // 添加Toast提示
            ToastService.Instance.ShowToast("发送超时", "串口设备未响应，请检查设备", ToastType.Error);
        }
        catch (InvalidOperationException ioex)
        {
            LogEntries.Add($"[ERROR] 发送失败：串口操作无效 - {ioex.Message}");
            LogEntries.Add("[INFO] 串口连接可能已中断，正在断开连接...");
            // 添加Toast提示
            ToastService.Instance.ShowToast("发送失败", "串口操作无效，连接可能已中断", ToastType.Error);
            DisconnectPort(); 
        }
        catch (IOException ioex)
        {
            LogEntries.Add($"[ERROR] 发送失败：I/O错误 - {ioex.Message}");
            LogEntries.Add("[提示] 串口设备可能已被拔出或硬件故障");
            // 添加Toast提示
            ToastService.Instance.ShowToast("发送失败", "I/O错误，设备可能已被拔出", ToastType.Error);
            DisconnectPort(); 
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] 发送失败：未知错误 - {ex.Message}");
            if (ex.InnerException != null)
            {
                LogEntries.Add($"[ERROR] 详细原因：{ex.InnerException.Message}");
            }
            // 添加Toast提示
            ToastService.Instance.ShowToast("发送失败", $"未知错误: {ex.Message}", ToastType.Error);
            
            // 如果是定时发送，发生错误时停止定时
            if (IsScheduled)
            {
                LogEntries.Add("[INFO] 由于发送错误，已停止定时发送");
                IsScheduled = false; 
            }
        }
    }

    // 辅助方法，确保在 UI 线程上添加消息
    private void AddLogMessage(LogMessage message)
    {
        Dispatcher.UIThread.InvokeAsync(() => _messages.Add(message));
    }

    private void RefreshAvailablePorts()
    {
        AvailablePorts.Clear();
        try
        {
            foreach (string portName in SerialPort.GetPortNames())
            {
                AvailablePorts.Add(portName);
            }

            if (AvailablePorts.Count > 0 && string.IsNullOrEmpty(SelectedPort))
            {
                SelectedPort = AvailablePorts[0];
            }
        }
        catch (Exception ex)
        {
            LogEntries.Add($"获取串口列表错误: {ex.Message}");
        }
    }

    private void ConnectPort()
    {
        if (string.IsNullOrEmpty(SelectedPort))
        {
            LogEntries.Add("[ERROR] 无法连接：未选择串口");
            // 添加Toast提示
            ToastService.Instance.ShowToast("连接失败", "未选择串口", ToastType.Error);
            return;
        }

        try
        {
            // 首先检查端口是否已经被占用
            bool portExists = SerialPort.GetPortNames().Contains(SelectedPort);
            if (!portExists)
            {
                LogEntries.Add($"[ERROR] 无法连接：串口 {SelectedPort} 不存在或已被移除");
                // 添加Toast提示
                ToastService.Instance.ShowToast("连接失败", $"串口 {SelectedPort} 不存在或已被移除", ToastType.Error);
                RefreshAvailablePorts(); // 自动刷新列表
                return;
            }

            // 创建并配置串口
            _serialPort = new SerialPort
            {
                PortName = SelectedPort,
                BaudRate = BaudRate,
                DataBits = SelectedDataBits, 
                Parity = SelectedParity,     
                StopBits = SelectedStopBits,
                ReadTimeout = 500,      // 添加超时设置
                WriteTimeout = 500      // 添加超时设置
            };

            LogEntries.Add($"[INFO] 正在连接到 {SelectedPort}...");
            
            // 尝试打开串口
            _serialPort.DataReceived += SerialPort_DataReceived;
            _serialPort.Open();
            _isConnected = true;
            
            LogEntries.Add($"[SUCCESS] 已成功连接到 {SelectedPort} ({BaudRate}波特率, {SelectedDataBits}数据位, {SelectedParity}校验位, {SelectedStopBits}停止位)");
            // 添加Toast提示
            ToastService.Instance.ShowToast("连接成功", $"已连接到 {SelectedPort}", ToastType.Success);
            OnPropertyChanged(nameof(ConnectionButtonText));
            OnPropertyChanged(nameof(ConnectionStatus));
        }
        catch (UnauthorizedAccessException)
        {
            LogEntries.Add($"[ERROR] 无法连接：串口 {SelectedPort} 已被其他程序占用");
            // 添加Toast提示
            ToastService.Instance.ShowToast("连接失败", $"串口 {SelectedPort} 已被其他程序占用", ToastType.Error);
            CleanupFailedConnection();
        }
        catch (IOException ioEx)
        {
            LogEntries.Add($"[ERROR] 无法连接：I/O错误 - {ioEx.Message}");
            LogEntries.Add("[提示] 可能是串口已被移除或存在硬件故障");
            // 添加Toast提示
            ToastService.Instance.ShowToast("连接失败", "I/O错误，可能是串口已被移除或硬件故障", ToastType.Error);
            CleanupFailedConnection();
            RefreshAvailablePorts(); // 自动刷新列表
        }
        catch (ArgumentException argEx)
        {
            LogEntries.Add($"[ERROR] 无法连接：参数错误 - {argEx.Message}");
            LogEntries.Add("[提示] 波特率、数据位、校验位或停止位设置可能不受该串口设备支持");
            // 添加Toast提示
            ToastService.Instance.ShowToast("连接失败", "参数错误，串口设置可能不受支持", ToastType.Error);
            CleanupFailedConnection();
        }
        catch (InvalidOperationException)
        {
            LogEntries.Add($"[ERROR] 无法连接：串口 {SelectedPort} 已经打开或状态无效");
            // 添加Toast提示
            ToastService.Instance.ShowToast("连接失败", $"串口 {SelectedPort} 已经打开或状态无效", ToastType.Error);
            CleanupFailedConnection();
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] 无法连接：未知错误 - {ex.Message}");
            if (ex.InnerException != null)
            {
                LogEntries.Add($"[ERROR] 详细原因：{ex.InnerException.Message}");
            }
            // 添加Toast提示
            ToastService.Instance.ShowToast("连接失败", $"未知错误: {ex.Message}", ToastType.Error);
            CleanupFailedConnection();
        }
    }

    // 清理失败的连接尝试资源
    private void CleanupFailedConnection()
    {
        if (_serialPort != null)
        {
            try
            {
                // 移除事件处理
                _serialPort.DataReceived -= SerialPort_DataReceived;
                
                // 如果端口已打开，尝试关闭它
                if (_serialPort.IsOpen)
                {
                    _serialPort.Close();
                }
                
                // 释放资源
                _serialPort.Dispose();
            }
            catch
            {
                // 忽略清理过程中的任何错误
            }
            finally
            {
                _serialPort = null;
                _isConnected = false;
                OnPropertyChanged(nameof(ConnectionButtonText));
                OnPropertyChanged(nameof(ConnectionStatus));
            }
        }
    }

    private void DisconnectPort()
    {
        StopScheduledSend(); // 断开连接时停止定时发送
        IsScheduled = false; // 同时取消勾选状态
        
        if (_serialPort == null) 
        {
            LogEntries.Add("[WARNING] 断开连接：无需断开，串口实例不存在");
            _isConnected = false;
            OnPropertyChanged(nameof(ConnectionButtonText));
            OnPropertyChanged(nameof(ConnectionStatus));
            return;
        }
        
        if (!_serialPort.IsOpen)
        {
            LogEntries.Add("[WARNING] 断开连接：串口已经处于关闭状态");
            _serialPort = null;
            _isConnected = false;
            OnPropertyChanged(nameof(ConnectionButtonText));
            OnPropertyChanged(nameof(ConnectionStatus));
            return;
        }
        
        try
        {
            LogEntries.Add($"[INFO] 正在断开串口 {_serialPort.PortName}...");
            
            // 移除事件处理器
            _serialPort.DataReceived -= SerialPort_DataReceived;
            
            // 关闭串口
            _serialPort.Close();
            _serialPort.Dispose();
            _serialPort = null;
            _isConnected = false;
            
            LogEntries.Add("[SUCCESS] 串口已成功断开");
            OnPropertyChanged(nameof(ConnectionButtonText));
            OnPropertyChanged(nameof(ConnectionStatus));
        }
        catch (InvalidOperationException invOpEx)
        {
            LogEntries.Add($"[ERROR] 断开连接失败：操作无效 - {invOpEx.Message}");
            // 尝试强制清理
            ForceCleanupPort();
        }
        catch (IOException ioEx)
        {
            LogEntries.Add($"[ERROR] 断开连接失败：I/O错误 - {ioEx.Message}");
            // 尝试强制清理
            ForceCleanupPort();
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] 断开连接失败：未知错误 - {ex.Message}");
            // 尝试强制清理
            ForceCleanupPort();
        }
    }
    
    // 强制清理串口资源的方法
    private void ForceCleanupPort()
    {
        try
        {
            LogEntries.Add("[INFO] 尝试强制清理串口资源...");
            if (_serialPort != null)
            {
                // 最后尝试释放资源
                _serialPort.Dispose();
                _serialPort = null;
            }
        }
        catch (Exception)
        {
            LogEntries.Add("[ERROR] 强制清理串口资源失败");
        }
        finally
        {
            _isConnected = false;
            OnPropertyChanged(nameof(ConnectionButtonText));
            OnPropertyChanged(nameof(ConnectionStatus));
            LogEntries.Add("[INFO] 串口连接状态已重置");
        }
    }

    private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        if (_serialPort == null)
        {
            Dispatcher.UIThread.InvokeAsync(() => 
            {
                LogEntries.Add("[ERROR] 数据接收失败：串口实例不存在");
                // 可能需要修正状态
                _isConnected = false;
                OnPropertyChanged(nameof(ConnectionButtonText));
                OnPropertyChanged(nameof(ConnectionStatus));
            });
            return;
        }

        if (!_serialPort.IsOpen)
        {
            Dispatcher.UIThread.InvokeAsync(() => 
            {
                LogEntries.Add("[ERROR] 数据接收失败：串口已断开连接");
                // 修正状态不一致
                _isConnected = false;
                OnPropertyChanged(nameof(ConnectionButtonText));
                OnPropertyChanged(nameof(ConnectionStatus));
            });
            return;
        }

        try
        {
            // 检查有多少字节可以读取
            int bytesToRead = _serialPort.BytesToRead;
            if (bytesToRead <= 0)
            {
                Dispatcher.UIThread.InvokeAsync(() => 
                    LogEntries.Add("[WARNING] 数据接收事件触发，但没有可读取的数据"));
                return;
            }

            // 创建缓冲区并读取数据
            byte[] buffer = new byte[bytesToRead];
            int bytesRead = _serialPort.Read(buffer, 0, bytesToRead);
            
            // 更新接收字节计数
            ReceivedBytes += bytesRead;

            // 显示和处理接收到的数据
            string receivedContent;
            if (HexDisplay)
            {
                receivedContent = BitConverter.ToString(buffer).Replace("-", " ");
            }
            else
            {
                try
                {
                    receivedContent = Encoding.UTF8.GetString(buffer);
                }
                catch (DecoderFallbackException)
                {
                    receivedContent = $"[解码失败] {BitConverter.ToString(buffer).Replace("-", " ")}";
                    Dispatcher.UIThread.InvokeAsync(() => 
                        LogEntries.Add("[WARNING] UTF-8解码失败，显示十六进制内容"));
                }
                catch (Exception)
                {
                    receivedContent = $"[解码失败] {BitConverter.ToString(buffer).Replace("-", " ")}";
                    Dispatcher.UIThread.InvokeAsync(() => 
                        LogEntries.Add("[ERROR] 内容解码时发生未知错误"));
                }
            }

            // 协议解析
            byte[]? parsedData = buffer;
            if (ProtocolConfig.IsEnabled)
            {
                parsedData = ProtocolService.Instance.ProcessReceivedData(buffer);
                if (parsedData == null)
                {
                    // 数据不完整或协议解析中，等待更多数据
                    return;
                }
                buffer = parsedData;
                bytesRead = buffer.Length;
            }

            // 创建日志消息对象
            var message = new LogMessage
            {
                Direction = LogMessageDirection.Received,
                Content = receivedContent,
                RawBytes = buffer
            };

            // 在UI线程上安全地更新界面
            Dispatcher.UIThread.InvokeAsync(() => 
            {
                _messages.Add(message);
                
                if (bytesRead > 0)
                {
                    // 当接收到的数据过多时，只显示简短摘要
                    string displayContent = receivedContent;
                    if (displayContent.Length > 100)
                    {
                        displayContent = displayContent.Substring(0, 97) + "...";
                    }
                    
                    LogEntries.Add($"[INFO] 接收到 {bytesRead} 字节数据: {displayContent}");
                }
            });
        }
        catch (TimeoutException)
        {
            Dispatcher.UIThread.InvokeAsync(() => 
                LogEntries.Add("[ERROR] 数据接收超时：串口设备未响应"));
        }
        catch (InvalidOperationException invOpEx)
        {
            Dispatcher.UIThread.InvokeAsync(() => 
            {
                LogEntries.Add($"[ERROR] 数据接收失败：串口操作无效 - {invOpEx.Message}");
                DisconnectPort(); // 尝试安全断开
            });
        }
        catch (IOException ioEx)
        {
            Dispatcher.UIThread.InvokeAsync(() => 
            {
                LogEntries.Add($"[ERROR] 数据接收失败：I/O错误 - {ioEx.Message}");
                LogEntries.Add("[提示] 串口设备可能已被拔出或发生硬件故障");
                DisconnectPort(); // 尝试安全断开
            });
        }
        catch (Exception ex)
        {
            Dispatcher.UIThread.InvokeAsync(() => 
            {
                LogEntries.Add($"[ERROR] 数据接收失败：未知错误 - {ex.Message}");
                if (ex.InnerException != null)
                {
                    LogEntries.Add($"[ERROR] 详细原因：{ex.InnerException.Message}");
                }
            });
        }
    }

    private static byte[] ConvertHexStringToByteArray(string hexString)
    {
        hexString = hexString.Replace(" ", string.Empty).Replace("\r", string.Empty).Replace("\n", string.Empty);
        if (hexString.Length % 2 != 0)
            throw new FormatException("HEX 字符串长度必须是偶数。");

        byte[] byteArray = new byte[hexString.Length / 2];
        for (int i = 0; i < byteArray.Length; i++)
        {
            string byteValue = hexString.Substring(i * 2, 2);
            byteArray[i] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
        }
        return byteArray;
    }

    // 新增：供 PresetCommandViewModel 调用的方法
    public async Task<bool> DeletePreset(PresetCommandViewModel presetViewModel) // 改为返回 Task<bool>
    {
        if (presetViewModel == null) 
            return false;
            
        // 添加确认对话框
        bool confirmDelete = await DialogService.Instance.ShowConfirmationAsync(
            "确认删除", 
            $"确定要删除预设命令 '{presetViewModel.Name}' 吗？", 
            "删除", "取消");
            
        if (confirmDelete)
        {
            PresetCommands.Remove(presetViewModel);
            LogEntries.Add($"已删除预设指令: {presetViewModel.Name}");
            SavePresets(); // <--- Add SavePresets call
            
            // 添加Toast提示
            ToastService.Instance.ShowToast("删除成功", $"预设命令 '{presetViewModel.Name}' 已删除", ToastType.Information);
            return true;
        }
        
        return false;
    }

    // 新增：仅将预设命令文本复制到主发送框
    public void CopyPresetCommandToMain(string commandString) // 改为 public
    {
        CommandToSend = commandString;
    }

    // 修改：直接发送预设指令而不更改主界面的方法
    public async Task SendPresetDirectly(string commandString, string encodingType)
    {
        LogEntries.Add($"[DEBUG] Sending preset directly. Command: '{commandString}', Encoding: '{encodingType}'");
        // 不再修改SelectedSendEncoding，而是直接传递encodingType作为参数
        // 执行发送逻辑，使用命令覆盖和编码覆盖参数
        await ExecuteSendLogic(commandOverride: commandString, encodingOverride: encodingType);
    }

    // +++ Add the following three methods +++
    private string GetPresetsFilePath()
    {
        string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
        string appFolderPath = Path.Combine(appDataPath, "SerialTool");
        // 确保目录存在
        Directory.CreateDirectory(appFolderPath); 
        return Path.Combine(appFolderPath, "presets.json");
    }

    private void SavePresets()
    {
        try
        {
            string filePath = GetPresetsFilePath();
            // 从 ViewModel 集合中提取 Model 列表 - 使用 Preset 而不是 PresetModel
            var presetModels = PresetCommands.Select(vm => vm.Preset).ToList(); 
            // 使用 System.Text.Json 进行序列化
            string jsonString = JsonSerializer.Serialize(presetModels, new JsonSerializerOptions { WriteIndented = true });
            File.WriteAllText(filePath, jsonString);
            LogEntries.Add("[INFO] Presets saved successfully.");
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] Failed to save presets: {ex.Message}");
        }
    }

    private void LoadPresets()
    {
        try
        { 
            string filePath = GetPresetsFilePath();
            if (File.Exists(filePath))
            {
                string jsonString = File.ReadAllText(filePath);
                // 使用 System.Text.Json 进行反序列化
                var presetModels = JsonSerializer.Deserialize<List<PresetCommand>>(jsonString);
                
                if (presetModels != null)
                {
                    PresetCommands.Clear(); // 清空现有（如果有的话）
                    foreach (var model in presetModels)
                    {
                        // 为每个加载的模型创建 ViewModel
                        PresetCommands.Add(new PresetCommandViewModel(model, this)); 
                    }
                    LogEntries.Add("[INFO] Presets loaded successfully.");
                }
            }
            else
            {
                 LogEntries.Add("[INFO] No preset file found. Starting with empty presets.");
            }
        }
        catch (JsonException jsonEx)
        {
            LogEntries.Add($"[ERROR] Failed to parse presets file (JSON invalid): {jsonEx.Message}");
            PresetCommands.Clear();
        }
        catch (Exception ex) // Catch other potential exceptions (IO, etc.)
        {
            LogEntries.Add($"[ERROR] Failed to load presets: {ex.Message}");
            PresetCommands.Clear(); 
        }
    }

    // 加载应用设置
    private void LoadSettings()
    {
        try
        {
            string filePath = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                "SerialTool", "settings.json");

            if (File.Exists(filePath))
            {
                string jsonString = File.ReadAllText(filePath);
                var settings = JsonSerializer.Deserialize<AppSettings>(jsonString);
                
                if (settings != null)
                {
                    // 应用设置到当前实例
                    _appSettings = settings;
                    
                    // 更新 ViewModel 属性
                    BaudRate = settings.BaudRate;
                    SelectedDataBits = settings.DataBits;
                    SelectedParity = settings.SelectedParity;
                    SelectedStopBits = settings.SelectedStopBits;
                    SelectedSendEncoding = settings.SelectedSendEncoding;
                    HexDisplay = settings.HexDisplay;
                    SendInterval = settings.SendInterval;
                    ShowSent = settings.ShowSent;
                    ShowReceived = settings.ShowReceived;
                    AutoScrollEnabled = settings.AutoScrollEnabled;

                    LogEntries.Add("[INFO] 应用设置已加载");

                    // 加载协议配置
                    try
                    {
                        // 设置活动协议类型
                        if (!string.IsNullOrEmpty(settings.ActiveProtocolType))
                        {
                            switch (settings.ActiveProtocolType)
                            {
                                case "Modbus":
                                    if (!string.IsNullOrEmpty(settings.ModbusSettings))
                                    {
                                        var modbusConfig = JsonSerializer.Deserialize<ModbusConfig>(settings.ModbusSettings);
                                        if (modbusConfig != null)
                                        {
                                            // 更新现有Modbus配置
                                            var existing = ProtocolConfig.Protocols.FirstOrDefault(p => p.ProtocolType == "Modbus") as ModbusConfig;
                                            if (existing != null)
                                            {
                                                existing.Mode = modbusConfig.Mode;
                                                existing.SlaveAddress = modbusConfig.SlaveAddress;
                                                existing.UseCRC = modbusConfig.UseCRC;
                                                existing.Timeout = modbusConfig.Timeout;
                                                existing.IsEnabled = modbusConfig.IsEnabled;
                                            }
                                            else
                                            {
                                                ProtocolConfig.Protocols.Add(modbusConfig);
                                            }
                                            
                                            ProtocolConfig.SelectedProtocolType = "Modbus";
                                        }
                                    }
                                    break;
                                    
                                case "Custom":
                                    if (!string.IsNullOrEmpty(settings.CustomProtocolSettings))
                                    {
                                        var customConfig = JsonSerializer.Deserialize<CustomProtocolConfig>(settings.CustomProtocolSettings);
                                        if (customConfig != null)
                                        {
                                            // 更新现有自定义协议配置
                                            var existing = ProtocolConfig.Protocols.FirstOrDefault(p => p.ProtocolType == "Custom") as CustomProtocolConfig;
                                            if (existing != null)
                                            {
                                                existing.StartDelimiter = customConfig.StartDelimiter;
                                                existing.EndDelimiter = customConfig.EndDelimiter;
                                                existing.UseChecksum = customConfig.UseChecksum;
                                                existing.Method = customConfig.Method;
                                                existing.PacketTimeout = customConfig.PacketTimeout;
                                                existing.IsEnabled = customConfig.IsEnabled;
                                            }
                                            else
                                            {
                                                ProtocolConfig.Protocols.Add(customConfig);
                                            }
                                            
                                            ProtocolConfig.SelectedProtocolType = "自定义";
                                        }
                                    }
                                    break;
                                    
                                default:
                                    ProtocolConfig.SelectedProtocolType = "无协议";
                                    break;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        LogEntries.Add($"[ERROR] 加载协议配置失败: {ex.Message}");
                    }
                }
            }
            else
            {
                LogEntries.Add("[INFO] 未找到设置文件，使用默认设置");
            }
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] 加载应用设置失败: {ex.Message}");
        }
    }

    // 保存应用设置
    private void SaveSettings()
    {
        try
        {
            // 更新设置对象
            _appSettings.BaudRate = BaudRate;
            _appSettings.DataBits = SelectedDataBits;
            _appSettings.SelectedParity = SelectedParity;
            _appSettings.SelectedStopBits = SelectedStopBits;
            _appSettings.SelectedSendEncoding = SelectedSendEncoding;
            _appSettings.HexDisplay = HexDisplay;
            _appSettings.SendInterval = SendInterval;
            _appSettings.ShowSent = ShowSent;
            _appSettings.ShowReceived = ShowReceived;
            _appSettings.AutoScrollEnabled = AutoScrollEnabled;

            // 保存到文件
            string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            string appFolderPath = Path.Combine(appDataPath, "SerialTool");
            Directory.CreateDirectory(appFolderPath);
            string filePath = Path.Combine(appFolderPath, "settings.json");

            string jsonString = JsonSerializer.Serialize(_appSettings, new JsonSerializerOptions { WriteIndented = true });
            File.WriteAllText(filePath, jsonString);
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] 保存应用设置失败: {ex.Message}");
        }
    }

    // 窗口状态管理方法
    public int GetWindowWidth() => _appSettings.WindowWidth;
    public int GetWindowHeight() => _appSettings.WindowHeight;
    public bool GetIsWindowMaximized() => _appSettings.IsMaximized;

    public void SetWindowSize(int width, int height)
    {
        if (width > 0 && height > 0)
        {
            _appSettings.WindowWidth = width;
            _appSettings.WindowHeight = height;
        }
    }

    public void SetIsWindowMaximized(bool isMaximized)
    {
        _appSettings.IsMaximized = isMaximized;
    }

    // 应用退出时保存设置
    public void SaveSettingsOnExit()
    {
        SaveSettings();
        SavePresets();
        LogEntries.Add("[INFO] 应用设置已保存");
    }

    // 添加协议配置保存方法
    public void SaveModbusSettings(ModbusConfig config)
    {
        try
        {
            string jsonString = JsonSerializer.Serialize(config);
            _appSettings.ModbusSettings = jsonString;
            _appSettings.ActiveProtocolType = "Modbus";
            SaveSettings();
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] 保存Modbus配置失败: {ex.Message}");
        }
    }
    
    public void SaveCustomProtocolSettings(CustomProtocolConfig config)
    {
        try
        {
            string jsonString = JsonSerializer.Serialize(config);
            _appSettings.CustomProtocolSettings = jsonString;
            _appSettings.ActiveProtocolType = "Custom";
            SaveSettings();
        }
        catch (Exception ex)
        {
            LogEntries.Add($"[ERROR] 保存自定义协议配置失败: {ex.Message}");
        }
    }
}
